Netty学习 您所在的位置:网站首页 java udp发送广播消息 Netty学习

Netty学习

2023-07-22 07:47| 来源: 网络整理| 查看: 265

什么是UDP协议?

UDP (User Datagram Protocol),全称为——用户数据报协议。UDP提供了一种无需建立连接就可以发送封装的IP数据包的方法。在OSI模型中处于传输层,IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 UDP报文结构 以上内容参考与百度百科:UDP

Netty实现UDP服务端与客户端

本次Demo参考《Netty权威指南》中的内容,在书中的示例上稍作了一些修改。主要实现了:

客户端向服务端发送“成语”或“谚语”时,服务端会随机生成对应的成语和谚语返回给客户端。服务端如果接收到除“谚语”和“成语”的其他字符串则发送“请发送‘谚语’或‘成语’”的提示语。客户端使用控制台可多次输入发送的内容 服务端代码 UdpServer.java package server; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; /** * UDP Server * * @author 胡海龙 * */ public class UdpServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true) .handler(new UdpServerHandler()); b.bind(8080).sync().channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } } UdpServerHandler.java package server; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; import io.netty.util.CharsetUtil; import io.netty.util.internal.ThreadLocalRandom; /** * UDP Server Handler Class * * @author 胡海龙 * */ public class UdpServerHandler extends SimpleChannelInboundHandler { private static final String[] proverbs = { "只要功夫深,铁棒磨成针。", "旧时王谢堂前燕,飞入寻常百姓家。", "洛阳亲友如相问,一片冰心在玉壶。", "一寸光阴一寸金,寸金难买寸光阴。", "老骥伏枥,志在千里。烈士暮年,壮心不已!" }; private static final String[] idioms = { "马到成功", "狐假虎威", "虎头虎脑", "生龙活虎", "如雷贯耳", "持之以恒" }; /** * 随机返回谚语 */ private String nextProverb() { int nextInt = ThreadLocalRandom.current().nextInt(proverbs.length); return proverbs[nextInt]; } /** * 随机返回成语 */ private String nextIdiom() { int nextInt = ThreadLocalRandom.current().nextInt(idioms.length); return idioms[nextInt]; } @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { String message = msg.content().toString(CharsetUtil.UTF_8); System.out.println("服务端接收到的消息:" + message); String sendMessage; if ("谚语".equals(message)) { sendMessage = nextProverb(); } else if ("成语".equals(message)) { sendMessage = nextIdiom(); } else { sendMessage = "请发送:“谚语”或者“成语”"; } ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(sendMessage, CharsetUtil.UTF_8), msg.sender())); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 客户端代码 UdpClient.java package server; import java.net.InetSocketAddress; import java.util.Scanner; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.util.CharsetUtil; /** * UDP Client * * @author 胡海龙 * */ public class UdpClient { public static void main(String[] args) throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true) .handler(new UdpClientHandler()); Channel channel = b.bind(8081).sync().channel(); Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String sendMessage = sc.next(); if ("quit".equals(sendMessage)) { break; } // 像网段内的所有广播机广播UDP消息 channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(sendMessage, CharsetUtil.UTF_8), new InetSocketAddress("255.255.255.255", 8080))); } sc.close(); channel.close(); } finally { group.shutdownGracefully(); } } } UdpClientHandler.java package server; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; import io.netty.util.CharsetUtil; /** * UDP Client Handler Class * * @author 胡海龙 * */ public class UdpClientHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { String receiveMessage = msg.content().toString(CharsetUtil.UTF_8); System.out.println(receiveMessage); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 代码解析

由于UDP不需要建立连接,所以只需要一个EventLoopGroup就可以,对应的channel类型也要改为NioDatagramChannel,SO_BROADCAST设置选项表示允许发送广播消息。在处理类中使用了SimpleChannelInboundHandler这个类,它时继承于ChannelInboundHandlerAdapter,它必须要实现的时channelRead0这个方法。源码如下;

package io.netty.channel; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.TypeParameterMatcher; public abstract class SimpleChannelInboundHandler extends ChannelInboundHandlerAdapter { private final TypeParameterMatcher matcher; private final boolean autoRelease; protected SimpleChannelInboundHandler() { this(true); } protected SimpleChannelInboundHandler(boolean autoRelease) { matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I"); this.autoRelease = autoRelease; } protected SimpleChannelInboundHandler(Class inboundMessageType) { this(inboundMessageType, true); } protected SimpleChannelInboundHandler(Class inboundMessageType, boolean autoRelease) { matcher = TypeParameterMatcher.get(inboundMessageType); this.autoRelease = autoRelease; } /** * 如果应该处理给定的消息则返回true,如果为false则会传递给到下一个处理类 * */ public boolean acceptInboundMessage(Object msg) throws Exception { return matcher.match(msg); } /** * 覆盖ChannelInboundHandlerAdapter 类的channelRead方法, * */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; channelRead0(ctx, imsg); } else { //被释放 release = false; ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { ReferenceCountUtil.release(msg); } } } protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception; }

UDP服务端和客户端的代码大致相同,只有在客户端有一点区别。客户端中使用广播地址对该网段的所有机器发送消息,当然也可以改为指定机器的IP。

运行截图

在这里插入图片描述

在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有